package com.googlecode.afx.view;

import java.util.ArrayList;
import java.util.List;

import com.googlecode.afx.AFXComponentCache;
import com.googlecode.afx.AFXMessageSource;
import com.googlecode.afx.AFXPrimaryStageHolder;
import com.googlecode.afx.view.behavior.ViewStateListener;
import com.googlecode.afx.view.behavior.ViewStateListenerNodeHandler;
import com.googlecode.afx.view.behavior.ViewStateManager;
import com.googlecode.afx.view.behavior.impl.ViewStateManagerImpl;
import com.googlecode.afx.view.validation.ValidationHandler;

import javafx.scene.Node;
import javafx.stage.Stage;

/**
 * Abstract class implementation for the <code>View</code> interface.
 * 
 * Implementing classes are responsible for constructing the JavaFX object
 * hierarchy of the <tt>Node</tt> instance.
 * 
 * @author MartinKoster
 *
 */
public abstract class AbstractView implements View {

	private String id;

	private Node node;

	private boolean maximized = false;

	private int sizeX = -1;

	private int sizeY = -1;

	private boolean modal = false;

	private String title = "";

	private String parentId;

	private AFXViewPosition position;

	private AFXComponentCache viewCache;

	private AFXPrimaryStageHolder primaryStageHolder;

	private AFXMessageSource messageSource;

	private ValidationHandler validationHandler;

	private List<ViewStateListener> viewStateListener;

	private ViewStateManager viewStateManager = new ViewStateManagerImpl(this);

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public Node getNode() {
		return node;
	}

	public void setNode(Node node) {
		this.node = node;
		if (this.node != null) {

			if (this.viewStateListener != null) {

				for (ViewStateListener listener : this.viewStateListener) {
					this.attachListenerToNodes(listener);
				}

			}
		}
	}

	public Stage getPrimaryStage() {
		return this.getPrimaryStageHolder() != null ? this.getPrimaryStageHolder().getPrimaryStage() : null;
	}

	public boolean isMaximized() {
		return maximized;
	}

	public void setMaximized(boolean maximized) {
		this.maximized = maximized;
	}

	public int getSizeX() {
		return sizeX;
	}

	public void setSizeX(int sizeX) {
		this.sizeX = sizeX;
	}

	public int getSizeY() {
		return sizeY;
	}

	public void setSizeY(int sizeY) {
		this.sizeY = sizeY;
	}

	public boolean isModal() {
		return modal;
	}

	public void setModal(boolean modal) {
		this.modal = modal;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getParentId() {
		return parentId;
	}

	public void setParentId(String parentId) {
		this.parentId = parentId;
	}

	public AFXViewPosition getPosition() {
		return position;
	}

	public void setPosition(AFXViewPosition position) {
		this.position = position;
	}

	public AFXComponentCache getViewCache() {
		return viewCache;
	}

	public void setViewCache(AFXComponentCache viewCache) {
		this.viewCache = viewCache;
	}

	public AFXPrimaryStageHolder getPrimaryStageHolder() {
		return primaryStageHolder;
	}

	public void setPrimaryStageHolder(AFXPrimaryStageHolder primaryStageHolder) {
		this.primaryStageHolder = primaryStageHolder;
	}

	public AFXMessageSource getMessageSource() {
		return messageSource;
	}

	public void setMessageSource(AFXMessageSource messageSource) {
		this.messageSource = messageSource;
	}

	public String getMessage(String code) {
		return this.getMessageSource().getMessage(code, null);
	}

	public String getMessage(String code, Object[] args) {
		return this.getMessageSource().getMessage(code, args);
	}

	public ValidationHandler getValidationHandler() {
		return validationHandler;
	}

	public void setValidationHandler(ValidationHandler validationHandler) {
		this.validationHandler = validationHandler;
	}

	@Override
	public void addListener(ViewStateListener listener) {
		if (listener == null) {
			throw new IllegalArgumentException("Argument 'listener' must not be null!");
		}
		if (this.viewStateListener == null) {
			this.viewStateListener = new ArrayList<ViewStateListener>();
		}
		this.viewStateListener.add(listener);
		if(this.node != null) {
			this.attachListenerToNodes(listener);
		}
	}

	public ViewStateManager getViewStateManager() {
		return viewStateManager;
	}

	public void setViewStateManager(ViewStateManager viewStateManager) {
		this.viewStateManager = viewStateManager;
	}

	/**
	 * Attaches the <tt>ViewStateListener</tt> to the nodes in the scene graph.
	 */
	protected void attachListenerToNodes(ViewStateListener listener) {
		// apply listener to every supported note, using the node
		// handler and adapter
		NodeWrapper.traverse(getNode(), new ViewStateListenerNodeHandler(getNode(), listener));
	}
	
	public abstract void show();

}
